<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>

    <link rel="stylesheet" type="text/css" 
      href="/assets/css/straybirds.css" media="screen" />
    <link rel="stylesheet" type="text/css" 
      href="/assets/css/pygments.css" media="screen" />

    <!-- MathJax Section Start -->

    <script type="text/javascript"
    src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
    </script>
    <script>
        MathJax.Hub.Config({
              tex2jax: {
              skipTags: ['script', 'noscript', 'style', 'textarea', 'pre']
              }
        });
        MathJax.Hub.Queue(function() {
            var all = MathJax.Hub.getAllJax(), i;
            for(i=0; i < all.length; i += 1) {
                all[i].SourceElement().parentNode.className += ' has-jax';
            }
        });
    </script>

    <!-- MathJax Section End -->

    <!-- Google Analytics Start-->
    <script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-48100787-1', 'minixalpha.github.io');
  ga('send', 'pageview');

</script>

    <!-- Google Analytics End -->

    <title>Category: 源代码阅读</title>
  </head>

  <body>
    <div class="container">
      <header>
        <div class="container">
          <h1>
              <a href="/" title="Home Page"> 潇湘夜雨 </a>
          <span class="github-src">
            <a href ="https://github.com/minixalpha/minixalpha.github.io"
               target="_blank"
               title="Fork me on GitHub">
              <img src="/assets/images/GitHub-Mark-Light-32px.png" alt="">
            </a>
          </span>
          </h1>
        </div>
      </header>

      <aside id="left-side">
        <h2> 分类 </h2>
  <ul class="category-list">
      
            
                <li>
                <a href="/categories/计算机系统"> 计算机系统 (3) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/java"> java (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/技术"> 技术 (5) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/工具"> 工具 (4) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/科研"> 科研 (5) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/生活"> 生活 (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/思想"> 思想 (2) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/c语言"> c语言 (4) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/虚拟机"> 虚拟机 (1) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/英语"> 英语 (8) </a>
                </li>
            
      
            
                <li>
                <a href="/categories/读书"> 读书 (1) </a>
                </li>
            
      
            
                <li style="background-color: #444">
                <a href="/categories/源代码阅读"> 源代码阅读 (10) </a>
                </li>
            
      
  </ul>

      </aside>

      <aside id="right-side">
        <h2> 归档 </h2>
  <ul class="archive-list">
    
    
    
        
        
        
        
            
            <li>
                <a href="/2014/05">
                    2014-05 (1)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/04">
                    2014-04 (3)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/03">
                    2014-03 (11)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/02">
                    2014-02 (6)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2014/01">
                    2014-01 (3)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2013/11">
                    2013-11 (10)
                </a>
            </li>

        
        
    
        
        
        
        
    
        
        
        
        
    
        
        
        
        
            
            <li>
                <a href="/2013/10">
                    2013-10 (3)
                </a>
            </li>

        
        
    
  </ul>

      </aside>

      <article>

<ul class="post-list">
  
    <li>
      <div class="post-title">
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2014/01/24/wsgiref-src-intro.html"> wsgiref 源代码分析</a> </br>
      </div>

      <div class="post-info">
        <ol>
          <li class="post-time">2014-01-24</li> 
          <li class="post-category"> 源代码阅读 </li>
        </ol>
      </div>

      <div class="post-preview">
        <h1>wsgiref 源代码分析</h1>

<h2>wsgiref</h2>

<p><a href="http://docs.python.org/2/library/wsgiref.html">wsgiref</a> 是Python标准库给出的 <a href="http://www.python.org/dev/peps/pep-0333/">WSGI</a> 的参考实现。</p>

<p>WSGI是Python Web 开发中为服务器程序和应用程序设定的标准，满足这一标准的服务器程序和应用程序可以配合使用。我在上一篇博文《<a href="http://blog.csdn.net/on_1y/article/details/18803563">WSGI简介</a>》中对此有详细的介绍。在阅读wsgiref源代码之前，一定要对WSGI有一定了解。</p>

<p>WSGI 在 <a href="http://www.python.org/dev/peps/pep-0333/">PEP 333</a> 中描述，但是只靠阅读PEP 333 可能在理解上还是不够深入，所以阅读官方给出的参考实现是很有必要的。阅读完这份源代码后，不仅有利于对WSGI的理解。而且会让你对服务端程序如何对客户端请求有一个直观的理解，从相对底层的socket监听请求，到上层对HTTP请求的处理。</p>

<p>当然，这只是对WSGI的参考实现，目的是为了描述清楚WSGI，而不是真正用在产品中。如果想对Python Web开发中服务器端的实现有更广泛，更深入的理解，需要进一步阅读Python常用框架的源代码。</p>

<h2>wsgiref 源代码分析</h2>

<p>wsgiref 源代码可以在 <a href="https://pypi.python.org/pypi/wsgiref">pypi wsgiref 0.1.2</a> 下载。另外，我在阅读的过程中作了大量注释，包含模块介绍，调用层次关系，demo的运行结果，等 等，还包含了阅读过程中制作的思维导图。GitHub地址<a href="https://github.com/minixalpha/SourceLearning/tree/master/wsgiref-0.1.2">注释版wsgiref</a>。</p>

<h3>结构</h3>

<p><img src="/assets/blog-images/wsgiref.bmp" alt="wsgiref"></p>

<p>上图描述了wsgiref的所有模块及模块间的调用关系，可以看出，wsgiref有以下模块：</p>

<ul>
<li><p>simple_server<br>
这一模块实现了一个简单的 HTTP 服务器，并给出了一个简单的 demo，运行：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">python simple_server.py
</code></pre></div></li>
</ul>

<p>会启动这个demo，运行一次请求，并把这次请求中涉及到的环境变量在浏览器中显示出来。</p>

<ul>
<li>handlers<br>
simple_server模块将HTTP服务器分成了 Server 部分和Handler部分，前者负责接收请求，后者负责具体的处理，
其中Handler部分主要在handlers中实现。</li>
<li>headers<br>
这一模块主要是为HTTP协议中header部分建立数据结构。</li>
<li>util<br>
这一模块包含了一些工具函数，主要用于对环境变量，URL的处理。</li>
<li>validate<br>
这一模块提供了一个验证工具，可以用于验证你的实现是否符合WSGI标准。</li>
</ul>

<h3>simple_server</h3>
 
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2014/01/24/wsgiref-src-intro.html"> Read More ... </a> </br>
      </div>

    </li>
  
    <li>
      <div class="post-title">
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/21/gmodules_arch.html"> web.py 项目架构分析之 googlemodules</a> </br>
      </div>

      <div class="post-info">
        <ol>
          <li class="post-time">2013-11-21</li> 
          <li class="post-category"> 源代码阅读 </li>
        </ol>
      </div>

      <div class="post-preview">
        <h1>web.py 项目之 googlemodules</h1>

<h2>项目说明</h2>

<p>项目来自 <a href="http://webpy.org/src/">webpy.org</a>, 这是一个真实的在线上运行的
项目: <a href="http://www.googlemodules.com/">Google Modules</a>, 可以上传，下载，
一些模块，还有一些评分，打标签等等功能。(不过这网站挺奇怪的。。。)</p>

<h2>目录树</h2>
<div class="highlight"><pre><code class="text language-text" data-lang="text">src/
    ├── application.py
    ├── forum.py
    ├── config_example.py
    ├── INSTALL
    ├── LICENCE
    ├── app
    │   ├── controllers
    │   ├── helpers
    │   ├── models
    │   └── views
    ├── app_forum
    │   ├── controllers
    │   ├── models
    │   └── views
    ├── data
    ├── public
    │   ├── css
    │   ├── img
    │   │   └── star
    │   ├── js
    │   └── rss
    ├── scripts
    └── sql

18 directories
</code></pre></div>
<p>终于遇到个稍微大一点的项目了，要好好看看。</p>

<p>从目录上看，整个项目分成两个部分，app 和 app_forum,每个部分都使用了
典型的MVC结构，将app分成 controllers, models, views 三大部分。</p>

<p>另外，网站使用的 css, js 文件，图片，也都统一放在了public目录下。</p>

<p>INSTALL 文件描述了如何安装部署项目, 包括在哪里下载项目，哪里下载web.py，如何
配置 lighttpd, 如何配置项目。</p>

<p>config_example.py 文件给了一个配置文件模板，按自己的需要修改其中内容，最后
把文件名改为 config.py 就可以了，其中包括对数据的配置，调试，缓存的开启等等。</p>

<p>LICENCE 文件描述了项目使用的开源协议: GPLv3。</p>

<p>项目使用的脚本放在scripts目录下，创建数据库使用的文件放在了sql目录下。</p>

<h2>代码统计</h2>

<p>先看看代码统计</p>

<p><img src="/assets/blog-images/googlemodules_code_stat.jpg" alt="googlemodules_code_stat.jpg"></p>

<h2>application 模块</h2>

<h3>application.py</h3>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="c">#!/usr/bin/env python</span>
<span class="c"># Author: Alex Ksikes </span>

<span class="c"># TODO: </span>
<span class="c"># - setup SPF for sendmail and </span>
<span class="c"># - emailerrors should be sent from same domain</span>
<span class="c"># - clean up schema.sql</span>
<span class="c"># - because of a bug in webpy unicode search fails (see models/sql_search.py)</span>

<span class="kn">import</span> <span class="nn">web</span>
<span class="kn">import</span> <span class="nn">config</span>
<span class="kn">import</span> <span class="nn">app.controllers</span>

<span class="kn">from</span> <span class="nn">app.helpers</span> <span class="kn">import</span> <span class="n">custom_error</span>

<span class="kn">import</span> <span class="nn">forum</span>

<span class="n">urls</span> <span class="o">=</span> <span class="p">(</span>        
    <span class="c"># front page</span>
    <span class="s">&#39;/&#39;</span><span class="p">,</span>                                    <span class="s">&#39;app.controllers.base.index&#39;</span><span class="p">,</span>
    <span class="s">&#39;/page/([0-9]+)/&#39;</span><span class="p">,</span>                      <span class="s">&#39;app.controllers.base.list&#39;</span><span class="p">,</span>

    <span class="c"># view, add a comment, vote</span>
    <span class="s">&#39;/module/([0-9]+)/&#39;</span><span class="p">,</span>                    <span class="s">&#39;app.controllers.module.show&#39;</span><span class="p">,</span>
    <span class="s">&#39;/module/([0-9]+)/comment/&#39;</span><span class="p">,</span>            <span class="s">&#39;app.controllers.module.comment&#39;</span><span class="p">,</span>
    <span class="s">&#39;/module/([0-9]+)/vote/&#39;</span><span class="p">,</span>               <span class="s">&#39;app.controllers.module.vote&#39;</span><span class="p">,</span>

    <span class="c"># submit a module</span>
    <span class="s">&#39;/submit/&#39;</span><span class="p">,</span>                             <span class="s">&#39;app.controllers.submit.submit&#39;</span><span class="p">,</span>

    <span class="c"># view author page</span>
    <span class="s">&#39;/author/(.*?)/&#39;</span><span class="p">,</span>                       <span class="s">&#39;app.controllers.author.show&#39;</span><span class="p">,</span>      

    <span class="c"># search browse by tag name</span>
    <span class="s">&#39;/search/&#39;</span><span class="p">,</span>                             <span class="s">&#39;app.controllers.search.search&#39;</span><span class="p">,</span>    
    <span class="s">&#39;/tag/(.*?)/&#39;</span><span class="p">,</span>                          <span class="s">&#39;app.controllers.search.list_by_tag&#39;</span><span class="p">,</span>

    <span class="c"># view tag clouds</span>
    <span class="s">&#39;/tags/&#39;</span><span class="p">,</span>                               <span class="s">&#39;app.controllers.cloud.tag_cloud&#39;</span><span class="p">,</span>
    <span class="s">&#39;/authors/&#39;</span><span class="p">,</span>                            <span class="s">&#39;app.controllers.cloud.author_cloud&#39;</span><span class="p">,</span>

    <span class="c"># table modules</span>
    <span class="s">&#39;/modules/(?:by-(.*?)/)?([0-9]+)?/?&#39;</span><span class="p">,</span>   <span class="s">&#39;app.controllers.all_modules.list_by&#39;</span><span class="p">,</span>

    <span class="c"># static pages</span>
    <span class="s">&#39;/feedback/&#39;</span><span class="p">,</span>                           <span class="s">&#39;app.controllers.feedback.send&#39;</span><span class="p">,</span>
    <span class="s">&#39;/about/&#39;</span><span class="p">,</span>                              <span class="s">&#39;app.controllers.base.about&#39;</span><span class="p">,</span>
    <span class="s">&#39;/help/&#39;</span><span class="p">,</span>                               <span class="s">&#39;app.controllers.base.help&#39;</span><span class="p">,</span>

    <span class="c"># let lighttpd handle in production</span>
    <span class="s">&#39;/(?:css|img|js|rss)/.+&#39;</span><span class="p">,</span>               <span class="s">&#39;app.controllers.public.public&#39;</span><span class="p">,</span>

    <span class="c"># canonicalize /urls to /urls/</span>
    <span class="s">&#39;/(.*[^/])&#39;</span><span class="p">,</span>                            <span class="s">&#39;app.controllers.public.redirect&#39;</span><span class="p">,</span>

    <span class="c"># mini forum app</span>
    <span class="s">&#39;/forum&#39;</span><span class="p">,</span>                               <span class="n">forum</span><span class="o">.</span><span class="n">app</span><span class="p">,</span>    

    <span class="s">&#39;/hello/(.*)&#39;</span><span class="p">,</span>                            <span class="s">&#39;hello&#39;</span><span class="p">,</span>

    <span class="c"># site admin app</span>
<span class="c">#    &#39;/admin&#39;,                              admin.app,    </span>
<span class="p">)</span>

<span class="n">app</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">application</span><span class="p">(</span><span class="n">urls</span><span class="p">,</span> <span class="nb">globals</span><span class="p">())</span>
<span class="n">custom_error</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
    <span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
</code></pre></div>
<p>可以看出，这是 application 部分的入口，这个模块仅仅是定义了各个请求的处理方式，
并完成程序的启动，所有的实现均不在这里出现，而是通过 <code>import</code> 导入，特别需要
注意 <code>urls</code> 最后定义的 <code>/forum</code> 和 <code>/admin</code> 使用了子程序，而不是通过之前的字符串
实现映射。还需要注意对静态文件,即css,js,img,rss文件的单独处理。</p>

<p>所有这些都与之前分析过的那些小项目不同，回想起我之前写的 
<a href="https://github.com/minixalpha/BlogSystem">BlogSystem</a>, 所有的处理实现都放在
同一个文件中，导致最后一个文件居然 700多行，真是让人潸然泪下。。。
而且之前也不知道使用子程序，所有处理都堆在一起。看来读完这份源代码，真应该重构一
下了。</p>

<h3>app 模块</h3>
<div class="highlight"><pre><code class="text language-text" data-lang="text">app/
    ├── models # 数据模块，MVC中的 M
    ├── views # 显示模块，MVC中的 V
    ├── controllers # 控制模块，MVC中的 C
    └── helpers # 辅助模块，实现辅助功能

4 directories
</code></pre></div>
<h3>controllers 模块</h3>
<div class="highlight"><pre><code class="text language-text" data-lang="text">controllers/
    ├── base.py         # 对基本页面，如网站主页,关于网页，帮助等的处理
    ├── all_modules.py  # 显示全部模块
    ├── module.py       # 对模块页面的处理
    ├── search.py       # 对搜索模块功能处理
    ├── submit.py       # 对提交模块的处理
    ├── author.py       # 查看模块作者信息
    ├── cloud.py        # 对标签云页面进行处理
    ├── feedback.py     # 处理反馈信息
    └── public.py       # 对静态文件的处理
</code></pre></div>
<p>这个模块主要是对请求处理的实现，在 <code>urls</code> 里定义的那些映射关系，
很多被映射到这里。</p>

<p>实现过程中，调用 models 模块对数据操作，再送入 views 模块通过模板引擎显示数据内容。</p>

<h3>models 模块</h3>
<div class="highlight"><pre><code class="text language-text" data-lang="text">models/
    ├── comments.py     # 对评论数据的处理
    ├── modules.py      # 对模块数据的处理
    ├── rss.py          # 对 rss 订阅的处理
    ├── sql_search.py   # 对搜索的数据处理
    ├── submission.py   # 对用户提交内容的处理
    ├── tags.py         # 对标签内容的数据处理
    └── votes.py        # 对用户投票的数据处理
</code></pre></div>
<p>这个模块直接调用 web.py 的db模块对数据库进行操作，对数据库的连接在 config.py 中
已经完成。这里完成数据的获取，处理，返回。可以看出，对不同种类的数据又分成了
很多小的模块。</p>
 
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/21/gmodules_arch.html"> Read More ... </a> </br>
      </div>

    </li>
  
    <li>
      <div class="post-title">
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/18/blog_arch.html"> web.py 项目架构分析之 blog</a> </br>
      </div>

      <div class="post-info">
        <ol>
          <li class="post-time">2013-11-18</li> 
          <li class="post-category"> 源代码阅读 </li>
        </ol>
      </div>

      <div class="post-preview">
        <h1>web.py 项目之 blog</h1>

<h2>目录树</h2>
<div class="highlight"><pre><code class="text language-text" data-lang="text">src/
├── blog.py
├── model.py
├── schema.sql
└── templates
    ├── base.html
    ├── edit.html
    ├── index.html
    ├── new.html
    └── view.html

1 directory, 8 files
</code></pre></div>
<h2>项目说明</h2>

<p>项目来自 <a href="http://webpy.org/src/blog/0.3">webpy.org</a>,
主要实现一个基于web的博客系统，实现了基本的增删查改。</p>

<h2>结构分析</h2>

<h3>控制模块</h3>

<p>控制模块包括 blog.py</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="sd">&quot;&quot;&quot; Basic blog using webpy 0.3 &quot;&quot;&quot;</span>
<span class="kn">import</span> <span class="nn">web</span>
<span class="kn">import</span> <span class="nn">model</span>

<span class="c">### Url mappings</span>

<span class="n">urls</span> <span class="o">=</span> <span class="p">(</span>
    <span class="s">&#39;/&#39;</span><span class="p">,</span> <span class="s">&#39;Index&#39;</span><span class="p">,</span>
    <span class="s">&#39;/view/(\d+)&#39;</span><span class="p">,</span> <span class="s">&#39;View&#39;</span><span class="p">,</span>
    <span class="s">&#39;/new&#39;</span><span class="p">,</span> <span class="s">&#39;New&#39;</span><span class="p">,</span>
    <span class="s">&#39;/delete/(\d+)&#39;</span><span class="p">,</span> <span class="s">&#39;Delete&#39;</span><span class="p">,</span>
    <span class="s">&#39;/edit/(\d+)&#39;</span><span class="p">,</span> <span class="s">&#39;Edit&#39;</span><span class="p">,</span>
<span class="p">)</span>
</code></pre></div> 
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/18/blog_arch.html"> Read More ... </a> </br>
      </div>

    </li>
  
    <li>
      <div class="post-title">
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/17/todolist_arch.html"> web.py 项目架构分析之 todolist</a> </br>
      </div>

      <div class="post-info">
        <ol>
          <li class="post-time">2013-11-17</li> 
          <li class="post-category"> 源代码阅读 </li>
        </ol>
      </div>

      <div class="post-preview">
        <h1>web.py 项目之 todolist</h1>

<h2>目录树</h2>
<div class="highlight"><pre><code class="text language-text" data-lang="text">.
└── src
    ├── model.py
    ├── schema.sql
    ├── templates
    │   ├── base.html
    │   └── index.html
    ├── todo.py

2 directories, 8 files
</code></pre></div>
<h2>项目说明</h2>

<p>项目来自 <a href="http://webpy.org/src/todo-list/0.3">webpy.org</a>,
主要实现一个基于web的 todolist，就是可以添加删除一些任务。
非常简单</p>

<h2>结构分析</h2>

<h3>控制模块</h3>

<p>控制模块只有todo.py</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="sd">&quot;&quot;&quot; Basic todo list using webpy 0.3 &quot;&quot;&quot;</span>
<span class="kn">import</span> <span class="nn">web</span>
<span class="kn">import</span> <span class="nn">model</span>

<span class="c">### Url mappings</span>

<span class="n">urls</span> <span class="o">=</span> <span class="p">(</span>
    <span class="s">&#39;/&#39;</span><span class="p">,</span> <span class="s">&#39;Index&#39;</span><span class="p">,</span>
    <span class="s">&#39;/del/(\d+)&#39;</span><span class="p">,</span> <span class="s">&#39;Delete&#39;</span>
<span class="p">)</span>
</code></pre></div> 
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/17/todolist_arch.html"> Read More ... </a> </br>
      </div>

    </li>
  
    <li>
      <div class="post-title">
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/14/skeleton_arch.html"> web.py 项目架构分析之 skeleton</a> </br>
      </div>

      <div class="post-info">
        <ol>
          <li class="post-time">2013-11-14</li> 
          <li class="post-category"> 源代码阅读 </li>
        </ol>
      </div>

      <div class="post-preview">
        <h1>web.py 项目之 skeleton</h1>

<p>skeleton 是 web.py 官网上给出的一个最简单的项目结构示例。</p>

<h2>目录树</h2>
<div class="highlight"><pre><code class="text language-text" data-lang="text">.
└── src  
    ├── code.py  
    ├── config.py  
    ├── db.py  
    ├── sql
    │   └── tables.sql
    ├── templates
    │   ├── base.html
    │   ├── item.html
    │   └── listing.html
    └── view.py

3 directories, 9 files
</code></pre></div>
<h2>结构分析</h2>

<h3>控制模块</h3>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="c">#code.py</span>

<span class="kn">import</span> <span class="nn">web</span>
<span class="kn">import</span> <span class="nn">view</span><span class="o">,</span> <span class="nn">config</span>
<span class="kn">from</span> <span class="nn">view</span> <span class="kn">import</span> <span class="n">render</span>

<span class="n">urls</span> <span class="o">=</span> <span class="p">(</span>
    <span class="s">&#39;/&#39;</span><span class="p">,</span> <span class="s">&#39;index&#39;</span>
<span class="p">)</span>

<span class="k">class</span> <span class="nc">index</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">GET</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">render</span><span class="o">.</span><span class="n">base</span><span class="p">(</span><span class="n">view</span><span class="o">.</span><span class="n">listing</span><span class="p">())</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
    <span class="n">app</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">application</span><span class="p">(</span><span class="n">urls</span><span class="p">,</span> <span class="nb">globals</span><span class="p">())</span>
    <span class="n">app</span><span class="o">.</span><span class="n">internalerror</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">debugerror</span>
    <span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
</code></pre></div>
<p><code>code</code> 模块作为入口:</p>

<ul>
<li>app 的创建与启动</li>
<li>url　与　处理类的映射与处理入口</li>
</ul>

<p>但是，具体的处理并不在这里实现。而是放在了 <code>view</code> 模块中。</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">这一模块是MVC中的C吗？
</code></pre></div>
<h3>显示模块</h3>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="c">#view.py</span>

<span class="kn">import</span> <span class="nn">web</span>
<span class="kn">import</span> <span class="nn">db</span>
<span class="kn">import</span> <span class="nn">config</span>

<span class="n">t_globals</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span>
  <span class="n">datestr</span><span class="o">=</span><span class="n">web</span><span class="o">.</span><span class="n">datestr</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">render</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">template</span><span class="o">.</span><span class="n">render</span><span class="p">(</span><span class="s">&#39;templates/&#39;</span><span class="p">,</span> <span class="n">cache</span><span class="o">=</span><span class="n">config</span><span class="o">.</span><span class="n">cache</span><span class="p">,</span> 
    <span class="nb">globals</span><span class="o">=</span><span class="n">t_globals</span><span class="p">)</span>
<span class="n">render</span><span class="o">.</span><span class="n">_keywords</span><span class="p">[</span><span class="s">&#39;globals&#39;</span><span class="p">][</span><span class="s">&#39;render&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">render</span>

<span class="k">def</span> <span class="nf">listing</span><span class="p">(</span>\<span class="o">**</span><span class="n">k</span><span class="p">):</span>
    <span class="n">l</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">listing</span><span class="p">(</span>\<span class="o">**</span><span class="n">k</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">render</span><span class="o">.</span><span class="n">listing</span><span class="p">(</span><span class="n">l</span><span class="p">)</span>
</code></pre></div>
<p>从这里可以看出　<code>view</code> 模块</p>

<ul>
<li>与模板关联 </li>
<li>从数据库中取数据，然后发给模板</li>
</ul>

<p>我们再来看看模板:</p>
<div class="highlight"><pre><code class="html language-html" data-lang="html"><span class="c">&lt;!--</span>
<span class="c">    templates/base.html</span>
<span class="c">--&gt;</span>

$def with (page, title=None)
<span class="nt">&lt;html&gt;&lt;head&gt;</span>
<span class="nt">&lt;title&gt;</span>my site\
$if title: : $title\
<span class="nt">&lt;/title&gt;</span>
<span class="nt">&lt;/head&gt;&lt;body&gt;</span>
<span class="nt">&lt;h1&gt;&lt;a</span> <span class="na">href=</span><span class="s">&quot;/&quot;</span><span class="nt">&gt;</span>my site<span class="nt">&lt;/a&gt;&lt;/h1&gt;</span>
$:page   
<span class="nt">&lt;/body&gt;&lt;/html&gt;</span>
</code></pre></div>
<p><code>base.html</code> 是所有模块的公共部分，每个模块只需要提供
它的 <code>page</code> ，即内容就可以了。</p>
<div class="highlight"><pre><code class="html language-html" data-lang="html"><span class="c">&lt;!--</span>
<span class="c">    templates/listing.html</span>
<span class="c">--&gt;</span>

$def with (items)

$for item in items:
    $:render.item(item)
</code></pre></div><div class="highlight"><pre><code class="text language-text" data-lang="text">这一模块是MVC中的V吗
</code></pre></div>
<h3>数据操作</h3>

<p>数据库操作分三部分</p>

<ul>
<li>sql/tables.sql 数据库表定义</li>
<li>config.py 数据库连接</li>
<li>db.py 数据库操作</li>
</ul>
<div class="highlight"><pre><code class="text language-text" data-lang="text">/* tables.sql */
CREATE TABLE items (
    id serial primary key,
    author_id int references users,
    body text,
    created timestamp default current_timestamp 
);
</code></pre></div><div class="highlight"><pre><code class="text language-text" data-lang="text">#config.py

import web
DB = web.database(dbn=&#39;mysql&#39;, db=&#39;skeleton&#39;, user=&#39;root&#39;, pw=&#39;xx&#39;)
cache = False
</code></pre></div><div class="highlight"><pre><code class="text language-text" data-lang="text"># db.py
import config

def listing(\**k):
    return config.DB.select(&#39;items&#39;, **k)
</code></pre></div><div class="highlight"><pre><code class="text language-text" data-lang="text">这是MVC中的M吗
</code></pre></div>
<p>这是 web.py 中最基本的一个项目结构。应该是使用的MVC设计模式。但是
因为程序本身不大，还体会不到 MVC 的好处。</p>
 
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/14/skeleton_arch.html"> Read More ... </a> </br>
      </div>

    </li>
  
    <li>
      <div class="post-title">
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/14/Application_testreloader.html"> web.py 源代码分析之　web.test.application.test_reloader</a> </br>
      </div>

      <div class="post-info">
        <ol>
          <li class="post-time">2013-11-14</li> 
          <li class="post-category"> 源代码阅读 </li>
        </ol>
      </div>

      <div class="post-preview">
        <h1>分模块测试</h1>

<h2>application.py</h2>

<p>对 application.py 的测试，调用命令：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">python test/application.py
</code></pre></div>
<h3>test_reloader(self)</h3>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">def</span> <span class="nf">test_reloader</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="n">write</span><span class="p">(</span><span class="s">&#39;foo.py&#39;</span><span class="p">,</span> <span class="n">data</span> <span class="o">%</span> <span class="nb">dict</span><span class="p">(</span><span class="n">classname</span><span class="o">=</span><span class="s">&#39;a&#39;</span><span class="p">,</span> <span class="n">output</span><span class="o">=</span><span class="s">&#39;a&#39;</span><span class="p">))</span>
    <span class="kn">import</span> <span class="nn">foo</span>
    <span class="n">app</span> <span class="o">=</span> <span class="n">foo</span><span class="o">.</span><span class="n">app</span>

    <span class="bp">self</span><span class="o">.</span><span class="n">assertEquals</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s">&#39;/&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="s">&#39;a&#39;</span><span class="p">)</span>

    <span class="c"># test class change</span>
    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
    <span class="n">write</span><span class="p">(</span><span class="s">&#39;foo.py&#39;</span><span class="p">,</span> <span class="n">data</span> <span class="o">%</span> <span class="nb">dict</span><span class="p">(</span><span class="n">classname</span><span class="o">=</span><span class="s">&#39;a&#39;</span><span class="p">,</span> <span class="n">output</span><span class="o">=</span><span class="s">&#39;b&#39;</span><span class="p">))</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">assertEquals</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s">&#39;/&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="s">&#39;b&#39;</span><span class="p">)</span>

    <span class="c"># test urls change</span>
    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
    <span class="n">write</span><span class="p">(</span><span class="s">&#39;foo.py&#39;</span><span class="p">,</span> <span class="n">data</span> <span class="o">%</span> <span class="nb">dict</span><span class="p">(</span><span class="n">classname</span><span class="o">=</span><span class="s">&#39;c&#39;</span><span class="p">,</span> <span class="n">output</span><span class="o">=</span><span class="s">&#39;c&#39;</span><span class="p">))</span>
    <span class="bp">self</span><span class="o">.</span><span class="n">assertEquals</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s">&#39;/&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="s">&#39;c&#39;</span><span class="p">)</span>
</code></pre></div>
<p>总的来说，这个过程会生成一个 foo.py 文件</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="kn">import</span> <span class="nn">web</span>

<span class="n">urls</span> <span class="o">=</span> <span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">,</span> <span class="s">&quot;a&quot;</span><span class="p">)</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">application</span><span class="p">(</span><span class="n">urls</span><span class="p">,</span> <span class="nb">globals</span><span class="p">(),</span> <span class="n">autoreload</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">a</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">GET</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">&quot;a&quot;</span>
</code></pre></div>
<p>这是一个典型的 web 服务端应用程序，表示对 <code>/</code> 发起 <code>GET</code>
请求时，会调用 <code>class a</code> 中的 <code>GET</code> 函数，测试就是看看
web.application 是否可以正常完成任务，即是否可以正确返回&quot;a&quot;</p>

<p>下面详细看代码。</p>

<p>首先使用 <code>write</code> 生成了一个 <code>foo.py</code> 程序:</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python">        <span class="n">write</span><span class="p">(</span><span class="s">&#39;foo.py&#39;</span><span class="p">,</span> <span class="n">data</span> <span class="o">%</span> <span class="nb">dict</span><span class="p">(</span><span class="n">classname</span><span class="o">=</span><span class="s">&#39;a&#39;</span><span class="p">,</span> <span class="n">output</span><span class="o">=</span><span class="s">&#39;a&#39;</span><span class="p">))</span>
</code></pre></div>
<p>write 源代码:</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">def</span> <span class="nf">write</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
    <span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="s">&#39;w&#39;</span><span class="p">)</span>
    <span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
    <span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</code></pre></div>
<p>data 定义:
```python
data = &quot;&quot;&quot;
import web</p>

<p>urls = (&quot;/&quot;, &quot;%(classname)s&quot;)
app = web.application(urls, globals(), autoreload=True)</p>

<p>class %(classname)s:
    def GET(self):
        return &quot;%(output)s&quot;</p>

<p>&quot;&quot;&quot;
```</p>

<p><code>data</code> 相当于一个小型 web 程序的模板，类名和返回值由
一个 <code>dict</code> 指定，生成一个字符串，由 <code>write</code> 生成文件。 </p>

<p>下面是类别和返回值为 <code>a</code> 时的 <code>foo.py</code></p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="kn">import</span> <span class="nn">web</span>

<span class="n">urls</span> <span class="o">=</span> <span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">,</span> <span class="s">&quot;a&quot;</span><span class="p">)</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">application</span><span class="p">(</span><span class="n">urls</span><span class="p">,</span> <span class="nb">globals</span><span class="p">(),</span> <span class="n">autoreload</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">a</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">GET</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">&quot;a&quot;</span>
</code></pre></div>
<p>测试的方式采用 <code>TestCase</code> 中的 <code>assertEquals</code> 函数，比较
实际值与预测值。</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="kn">import</span> <span class="nn">foo</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">foo</span><span class="o">.</span><span class="n">app</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEquals</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">request</span><span class="p">(</span><span class="s">&#39;/&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="s">&#39;a&#39;</span><span class="p">)</span>
</code></pre></div>
<p><code>app.request(&#39;/&#39;)</code> 会得到一个Storage类型的值：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">&lt;Storage {&#39;status&#39;: &#39;200 OK&#39;, &#39;headers&#39;: {}, &#39;header_items&#39;: [], &#39;data&#39;: &#39;a&#39;}&gt;
</code></pre></div>
<p>其中的 <code>data</code> 就是 <code>foo.py</code> 中 <code>GET</code> 返回的值。 </p>

<p>我对这个 <code>app.request(&#39;/&#39;)</code> 是比较困惑的。以 <code>foo.py</code> 为例，
之前写程序时，一般是有一个这样的程序：</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="kn">import</span> <span class="nn">web</span>

<span class="n">urls</span> <span class="o">=</span> <span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">,</span> <span class="s">&quot;a&quot;</span><span class="p">)</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">application</span><span class="p">(</span><span class="n">urls</span><span class="p">,</span> <span class="nb">globals</span><span class="p">(),</span> <span class="n">autoreload</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">a</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">GET</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">&quot;a&quot;</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
    <span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
</code></pre></div>
<p>然后在浏览器中请求 <code>0.0.0.0:8080/</code> 。
而在 <code>request</code> 之前，也没看到 <code>run</code> 啊，怎么就能 <code>request</code> 回
数据呢，而且通过上述代码运行后，程序会一直运行直到手动关闭，
而 <code>request</code> 的方式则是测试完后，整个程序也结束了。</p>

<p>所以，下一部，想比较一下 <code>application.run</code> 和 <code>application.request</code> 的不同。</p>

<p>我们只看关键部分，即返回的值是如何被设值的。</p>

<p>在 <code>web.application.request</code> 中:</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">localpart</span><span class="o">=</span><span class="s">&#39;/&#39;</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="s">&#39;GET&#39;</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span>
            <span class="n">host</span><span class="o">=</span><span class="s">&quot;0.0.0.0:8080&quot;</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">https</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="o">**</span><span class="n">kw</span><span class="p">):</span>

    <span class="o">...</span>

<span class="n">response</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">storage</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">start_response</span><span class="p">(</span><span class="n">status</span><span class="p">,</span> <span class="n">headers</span><span class="p">):</span>
    <span class="n">response</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="n">status</span>
    <span class="n">response</span><span class="o">.</span><span class="n">headers</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">headers</span><span class="p">)</span>
    <span class="n">response</span><span class="o">.</span><span class="n">header_items</span> <span class="o">=</span> <span class="n">headers</span>
<span class="n">response</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">wsgifunc</span><span class="p">()(</span><span class="n">env</span><span class="p">,</span> <span class="n">start_response</span><span class="p">))</span>
<span class="k">return</span> <span class="n">response</span>
</code></pre></div>
<p>上述代码中 <code>self.wsgifunc()(env, start_response)</code> 比较另人困惑，
我还以为是调用函数的新方式呢，然后看了一下 <code>wsgifunc</code> 的代码，
它会返回一个函数<code>wsgi</code>，<code>wsgi</code>以 <code>(env, start_response)</code> 为参数。
在 <code>wsgi</code> 内部，又会调用 <code>handle_with_processors</code>, <code>handle_with_processors</code> 会再调用 <code>handle</code></p>
<div class="highlight"><pre><code class="python language-python" data-lang="python">    <span class="k">def</span> <span class="nf">handle</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="n">fn</span><span class="p">,</span> <span class="n">args</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_match</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">mapping</span><span class="p">,</span> <span class="n">web</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">path</span><span class="p">)</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_delegate</span><span class="p">(</span><span class="n">fn</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">fvars</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span>
</code></pre></div>
<p>测试了一下，<code>self._match()</code> 会得到类名, <code>self._delegate</code> 会
得到返回的字符串，即 <code>GET</code>的返回值。</p>

<p>进入 <code>self._delegate</code>, 会最终调用一个关键函数 <code>handle_class</code>:</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">def</span> <span class="nf">handle_class</span><span class="p">(</span><span class="n">cls</span><span class="p">):</span>
    <span class="n">meth</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">ctx</span><span class="o">.</span><span class="n">method</span>
    <span class="k">if</span> <span class="n">meth</span> <span class="o">==</span> <span class="s">&#39;HEAD&#39;</span> <span class="ow">and</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="n">meth</span><span class="p">):</span>
        <span class="n">meth</span> <span class="o">=</span> <span class="s">&#39;GET&#39;</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="n">meth</span><span class="p">):</span>
        <span class="k">raise</span> <span class="n">web</span><span class="o">.</span><span class="n">nomethod</span><span class="p">(</span><span class="n">cls</span><span class="p">)</span>
    <span class="n">tocall</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">cls</span><span class="p">(),</span> <span class="n">meth</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">tocall</span><span class="p">(</span>\<span class="o">*</span><span class="n">args</span><span class="p">)</span>
</code></pre></div>
<p>参数<code>cls</code>值为<code>foo.a</code>, <code>meth</code> 会得到方法名 <code>GET</code>, 然后
<code>tocall</code> 会得到函数 <code>a.GET</code>, 至此，我们终于得以调用，
<code>GET</code>函数，得到了返回的字符串。</p>

<p>从整个过程可以看出，没有启动服务器的代码，只是不断地调用
函数，最终来到 <code>GET</code> 函数。</p>
 
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/14/Application_testreloader.html"> Read More ... </a> </br>
      </div>

    </li>
  
    <li>
      <div class="post-title">
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/14/Application_testUppercaseMethods.html"> web.py 源代码分析之 web.test.application.test_UppercaseMethods</a> </br>
      </div>

      <div class="post-info">
        <ol>
          <li class="post-time">2013-11-14</li> 
          <li class="post-category"> 源代码阅读 </li>
        </ol>
      </div>

      <div class="post-preview">
        <h1>分模块测试</h1>

<h2>application.py</h2>

<p>对 application.py 的测试，调用命令：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">python test/application.py
</code></pre></div> 
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/14/Application_testUppercaseMethods.html"> Read More ... </a> </br>
      </div>

    </li>
  
    <li>
      <div class="post-title">
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/14/Application_testRedirect.html"> web.py 源代码分析之 web.test.application.testRedirect</a> </br>
      </div>

      <div class="post-info">
        <ol>
          <li class="post-time">2013-11-14</li> 
          <li class="post-category"> 源代码阅读 </li>
        </ol>
      </div>

      <div class="post-preview">
        <h1>分模块测试</h1>

<h2>application.py</h2>

<p>对 application.py 的测试，调用命令：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">python test/application.py
</code></pre></div> 
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/14/Application_testRedirect.html"> Read More ... </a> </br>
      </div>

    </li>
  
    <li>
      <div class="post-title">
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/14/Application_intro.html"> web.py 源代码分析之　web.test.application</a> </br>
      </div>

      <div class="post-info">
        <ol>
          <li class="post-time">2013-11-14</li> 
          <li class="post-category"> 源代码阅读 </li>
        </ol>
      </div>

      <div class="post-preview">
        <h2>分模块测试</h2>

<h3>application.py</h3>

<p>对 application.py 的测试，调用命令：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">python test/application.py
</code></pre></div> 
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/14/Application_intro.html"> Read More ... </a> </br>
      </div>

    </li>
  
    <li>
      <div class="post-title">
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/14/Application_TestFrame.html"> web.py 源代码分析之 web.test 主要文件及测试流程</a> </br>
      </div>

      <div class="post-info">
        <ol>
          <li class="post-time">2013-11-14</li> 
          <li class="post-category"> 源代码阅读 </li>
        </ol>
      </div>

      <div class="post-preview">
        <h1>目录文件说明</h1>

<h2>README</h2>

<p>如何运行测试文件，包含全部测试及分模块测试</p>

<p>调用</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">$ python test/alltests.py
</code></pre></div>
<p>运行全部测试</p>

<p>调用</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">$ python test/db.py
</code></pre></div>
<p>运行db模块测试</p>

<h2>alltest.py</h2>

<p>运行全部测试入口，调用 <code>webtest</code> 模块完成测试</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="c"># alltest.py</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&quot;__main__&quot;</span><span class="p">:</span>
    <span class="n">webtest</span><span class="o">.</span><span class="n">main</span><span class="p">()</span>
</code></pre></div>
<h2>webtest.py</h2>

<p>我们发现 webtest.py 中并没有 main 函数，而是从 <code>web.test</code> 中导入，</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="c"># webtest.py</span>
<span class="kn">from</span> <span class="nn">web.test</span> <span class="kn">import</span> <span class="o">*</span>
</code></pre></div>
<p>也就是说，如果 <code>web.test</code>中有main函数的话，<code>webtest.main()</code>
其实是调用 <code>web.test</code> 中的main函数。</p>

<p>感觉～ 好神奇</p>

<h2>web.test</h2>

<p>看web目录下的test.py文件，果然发现了main函数，终于找到入口啦~</p>
<div class="highlight"><pre><code class="python language-python" data-lang="python"><span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">suite</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">suite</span><span class="p">:</span>
        <span class="n">main_module</span> <span class="o">=</span> <span class="nb">__import__</span><span class="p">(</span><span class="s">&#39;__main__&#39;</span><span class="p">)</span>
        <span class="c"># allow command line switches</span>
        <span class="n">args</span> <span class="o">=</span> <span class="p">[</span><span class="n">a</span> <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">a</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&#39;-&#39;</span><span class="p">)]</span>
        <span class="n">suite</span> <span class="o">=</span> <span class="n">module_suite</span><span class="p">(</span><span class="n">main_module</span><span class="p">,</span> <span class="n">args</span> <span class="ow">or</span> <span class="bp">None</span><span class="p">)</span>

    <span class="n">result</span> <span class="o">=</span> <span class="n">runTests</span><span class="p">(</span><span class="n">suite</span><span class="p">)</span>
    <span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="ow">not</span> <span class="n">result</span><span class="o">.</span><span class="n">wasSuccessful</span><span class="p">())</span>
</code></pre></div>
<p>把这个main函数改掉，再运行一下：</p>
<div class="highlight"><pre><code class="text language-text" data-lang="text">$ python test/alltests.py
</code></pre></div>
<p>果然是运行修改后的函数，所以这里确定是入口。</p>

<p>在进入下一步之前，我们需要学习一下Python自动单元测试框架，即<code>unittest</code>模块。关于 <code>unittest</code> ，可以参考这篇文章：
<a href="http://www.ibm.com/developerworks/cn/linux/l-pyunit/">Python自动单元测试框架</a></p>
 
        <a href="/%E6%BA%90%E4%BB%A3%E7%A0%81%E9%98%85%E8%AF%BB/2013/11/14/Application_TestFrame.html"> Read More ... </a> </br>
      </div>

    </li>
  
</ul>


      </article>

      <div class="comments">
        
      </div>


      <footer>
        Copyright (c) minixalpha 2014
      </footer>

    </div>
  </body>
</html>
